package org.zjx.server;

import lombok.SneakyThrows;
import org.zjx.core.SocketConfig;
import org.zjx.handler.CommandHandler;
import org.zjx.handler.CommandHandlerFactory;

import java.io.Closeable;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public abstract class BaseSocketServer implements Closeable {
    protected final SocketConfig config;
    protected ServerSocket serverSocket;
    protected ExecutorService threadPool;
    protected volatile boolean running = false;
    protected final SimpleDateFormat logFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    public BaseSocketServer(SocketConfig config) {
        this.config = config;
    }

    public void registerHandler(CommandHandler handler) {
        CommandHandlerFactory.registerHandler(handler);
    }

    public final void start() {
        if (!running) {
            initializeServer();
            startAcceptingConnections();
        }
    }

    public final void stop() {
        running = false;
        shutdownGracefully();
    }

    protected abstract void handleConnection(Socket clientSocket);

    @SneakyThrows
    protected void initializeServer() {
        serverSocket = new ServerSocket(config.getPort());
        threadPool = Executors.newFixedThreadPool(config.getMaxConnections(),
                r -> new Thread(r, "Server-Worker-" + r.hashCode()));
        running = true;
        logInfo("Server started on port " + config.getPort());
    }

    protected void startAcceptingConnections() {
        new Thread(() -> {
            while (running && !Thread.currentThread().isInterrupted()) {
                try {
                    Socket clientSocket = serverSocket.accept();
                    threadPool.execute(() -> handleConnection(clientSocket));
                } catch (IOException e) {
                    if (running) logError("Accept connection failed", e);
                }
            }
        }, "Acceptor-Thread").start();
    }

    protected void shutdownGracefully() {
        stopThreadPool();
        closeServerSocket();
        logInfo("Server stopped");
    }

    @SneakyThrows
    protected void stopThreadPool() {
        if (threadPool != null) {
            threadPool.shutdown();
            try {
                if (!threadPool.awaitTermination(5, TimeUnit.SECONDS)) {
                    threadPool.shutdownNow();
                }
            } catch (InterruptedException e) {
                threadPool.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    @SneakyThrows
    protected void closeServerSocket() {
        if (serverSocket != null && !serverSocket.isClosed()) {
            serverSocket.close();
        }
    }

    protected String formatLog(String level, String message) {
        return String.format("[%s] [%s] %s",
                logFormatter.format(new Date()), level, message);
    }

    protected void logInfo(String message) {
        System.out.println(formatLog("INFO", message));
    }

    protected void logWarn(String message) {
        System.err.println(formatLog("WARN", message));
    }

    protected void logError(String message, Throwable e) {
        System.err.println(formatLog("ERROR", message));
        if (e != null) e.printStackTrace(System.err);
    }

    @Override
    public void close() throws IOException {
        stop();
    }

    /**
     * 安全关闭Socket连接（不抛出异常）
     */
    protected void closeQuietly(Socket socket) {
        if (socket != null && !socket.isClosed()) {
            try {
                if (!socket.isInputShutdown()) socket.shutdownInput();
                if (!socket.isOutputShutdown()) socket.shutdownOutput();
            } catch (IOException ignored) {
            } finally {
                try {
                    if (!socket.isClosed()) socket.close();
                } catch (IOException ignored) {
                }
            }
        }
    }

    /**
     * 安全关闭流资源（不抛出异常）
     */
    protected void closeQuietly(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException ignored) {
            }
        }
    }
}